home *** CD-ROM | disk | FTP | other *** search
- /*
- * PrintJPEG.c
-
- Authored by: David Gelphman 6/9/95. Borrowed liberally from the JFIF-PICT
- conversion program provided as a sample program in the QuickTime development
- portion of the MacOS SDK.
-
- This is essentially the same as the PrintJPEG application but allows for a QuickTime
- data loading function to be used instead of loading all the data into memory.
-
- Copyright (c) Apple Computer Incorporated. All rights reserved.
- */
- #include "PrintJPEG with dataload.h"
-
- /* globals */
-
- WindowPtr gTheWindow;
- JPEGImage gTheJPEGImage;
- THPrint gPrinterRecord = NULL;
- ICMDataProcRecord gTheICMDataProcRecord;
-
- /* main */
- SInt16 main()
- {
- OSErr theErr;
- DataLoadPtr myDataLoadPtr;
-
- // initialize the managers and the menus
- if (initMacintosh() != noErr)
- return 0;
-
- /* allocate a print record for us */
- gPrinterRecord = (THPrint)NewHandle(sizeof( TPrint ) );
-
- // Get the defaults for the current printer driver.
- if (gPrinterRecord != NULL && MemError() == noErr)
- {
- PrOpen();
- PrintDefault( gPrinterRecord );
- PrClose();
- }else{
- ParamText("\pCan't allocate Print Record.", "\p", "\p", "\p");
- Alert(kGenericError, NULL);
- return iMemFullErr;
- }
-
- // Check to see if there are any errors and report them if they occur.
- if(( theErr = PrError()) != noErr){
- Str255 scratchString;
- NumToString((long)theErr, scratchString);
- ParamText("\pCan't Do PrDefault for some reason.", scratchString, "\p", "\p");
- Alert(kGenericError, NULL);
- }
-
- // make a new ICMDataProc record for using a DataLoading proc with *our* DataLoading
- // proc 'MyDataLoadingProc'.
- gTheICMDataProcRecord.dataProc = NewICMDataProc(MyDataLoadingProc);
-
- if(gTheICMDataProcRecord.dataProc != NULL && (MemError() == noErr) ){
-
- // make a pointer the size of the DataLoad data structure (defined in our .h file)
- // and put it into the 'dataRefCon' field of our ICMDataProc structure.
- gTheICMDataProcRecord.dataRefCon = (long)NewPtr(sizeof(DataLoad));
- }
-
- myDataLoadPtr = (DataLoadPtr)gTheICMDataProcRecord.dataRefCon;
-
- if(gTheICMDataProcRecord.dataRefCon != NULL && (MemError() == noErr) ){
- // make a new handle the size of our buffersize and put it into our DataLoad structure.
- myDataLoadPtr->theDataBufferH = NewHandle(kMYBUFFERSIZE);
-
- // fill in the size field too.
- myDataLoadPtr->theBufferSize = kMYBUFFERSIZE;
- // initialize the refnum field to zero.
- myDataLoadPtr->theRefNum = 0;
- }
-
- // make sure we could get the memory for our buffer
- if(myDataLoadPtr->theDataBufferH == NULL || MemError() != noErr){
- ParamText("\pCan't allocate Data Loading Buffer", "\p", "\p", "\p");
- Alert(kGenericError, NULL);
- return 1;
- }
-
-
- // initialize our JPEGImage Data Structure.
- gTheJPEGImage.theRefNum = 0;
- SetRect(&gTheJPEGImage.theBounds,0,0,0,0);
- gTheJPEGImage.theDesc = NULL;
-
- // Go ahead and get an image...
- DoTheOpenCommand();
-
- // Process events, etc.
- for (; handleEvent();)
- {
- } /* for */
- return 1;
- } /* main */
-
-
- //=====================================================================================
- // OSErr DrawJPEGImage(JPEGImage theJPEGImage, Boolean isColorPort)
- //=====================================================================================
- // Draws a JPEG image, whose data is on disk, to the current port.
- //=====================================================================================
-
-
- static OSErr DrawJPEGImage(JPEGImage theJPEGImage, Boolean isColorPort)
- {
- Rect srcRect;
-
- OSErr theErr = noErr;
-
- DataLoadPtr myDataLoadPtr = (DataLoadPtr)gTheICMDataProcRecord.dataRefCon;
- long theBufferSize = myDataLoadPtr->theBufferSize;
- short theRefNum = theJPEGImage.theRefNum;
-
- Handle theDataHandle = myDataLoadPtr->theDataBufferH;
- Ptr theDataPtr ;
- long theAmountToRead;
- ICMDataProcRecord *theDataProcRecord;
-
- ImageDescriptionHandle theDesc = theJPEGImage.theDesc;
-
- if (theDataHandle != NULL){
- PixMapHandle dPixMap = ((CGrafPtr)qd.thePort)->portPixMap;
-
- char hState = HGetState(theDataHandle);
- HLock(theDataHandle); // Lock down the data before using *theDataHandle
- theDataPtr = StripAddress(*theDataHandle);
-
- // srcRect will be the source rectangle of the image we will draw
- SetRect(&srcRect, 0, 0, (*theDesc)->width, (*theDesc)->height);
-
- // set up the data loading procedure, as necessary.
-
- // how much data should we read? It is the smaller of the size of the image or
- // our buffer size.
- theAmountToRead = MIN(theBufferSize, (*theDesc)->dataSize );
-
- // make sure we're at the beginning of the file before we start reading data.
- if(theErr == noErr)theErr = SetFPos(theRefNum, fsFromStart, 0);
-
- // fill up the buffer with the appropriate amt of data. This is either all the
- // data we need or one buffer's worth
- if(theErr == noErr)theErr = FSRead(theRefNum, &theAmountToRead,theDataPtr);
-
- if(theErr == noErr) {
- // if the amount of data read is the same as the size of the image, then
- // we don't need a data loading proc.
- if(theAmountToRead == (*theDesc)->dataSize){
- theDataProcRecord = NULL;
-
- // this will be used in FDecompressImage or StdPix since we aren't using a
- // data loading proc.
- theAmountToRead = 0;
- }else{
- // We come here if we need to use a data loading proc. By setting theDataProcRecord
- // to our ICMDataProcRecord we will use the data loading proc we've set up.
-
- theDataProcRecord = &gTheICMDataProcRecord;
- }
-
- if(isColorPort){
- MatrixRecord theMatrix;
- CQDProcs myStdProcs;
- StdPixProcPtr MyProcPtr;
- // set both flag bits described in IM QuickTime p.3-139 for StdPix
- short flags = kCallOldBits | kCallStdBits;
-
- // we need a pixmap for our call to the StdPix bottleneck
- PixMapHandle SpecialPixMapH = NewPixMap();
- PixMapPtr SpecialPixMapP;
-
- if(SpecialPixMapH != NULL && MemError() == noErr){
-
- MoveHHi((Handle)SpecialPixMapH);
- HLock((Handle)SpecialPixMapH);
-
- SpecialPixMapP = (PixMapPtr)StripAddress(*(Handle)SpecialPixMapH);
-
- // make a matrix which describes the mapping between the source
- // and destination rectangles. In our case, they will be the
- // same rectangle
-
- RectMatrix(&theMatrix, &srcRect, &srcRect);
-
- // SetCompressedPixMapInfo makes a compressed 'PixMap' structure into SpecialPixMapP, using
- // the ImageDescription in 'theDesc' with the compressed image data in 'theDataPtr'
-
- // We've set this up so if all the data is in memory then theAmountToRead is zero
- // and theDataProcRecord is NULL. If we need to use a dataloading proc, then
- // theAmountToRead is the size of our buffer and theDataProcRecord is our ICMDataProcRecord.
-
- theErr = SetCompressedPixMapInfo(SpecialPixMapP, theDesc, theDataPtr, theAmountToRead,theDataProcRecord,NULL);
-
- if(theErr == noErr){
- // Look to see if there are custom QuickDraw bottlenecks in the current port.
- if( (((CGrafPtr)qd.thePort)->grafProcs) == NULL)
- {
- // Get the Standard Bottleneck procs.
- SetStdCProcs(&myStdProcs);
-
- // The 'newProc1' bottleneck is the 'StdPix' bottleneck.
- MyProcPtr = (StdPixProcPtr)myStdProcs.newProc1;
-
- }else{
- // Use the custom 'StdPix' bottleneck in the grafPort.
- // The 'newProc1' bottleneck is the 'StdPix' bottleneck.
-
- MyProcPtr = (StdPixProcPtr)((CGrafPtr)qd.thePort)->grafProcs->newProc1;
- }
-
- // Call the bottleneck. The function call being used here is:
- // StdPix(SpecialPixMapP, &srcRect, &theMatrix, ditherCopy, NULL, NULL,NULL,flags)
- // with the appropriate StdPix bottleneck.
-
- CallStdPixProc(MyProcPtr,SpecialPixMapP, &srcRect, &theMatrix,
- ditherCopy, NULL, NULL,NULL,flags );
- }
- HUnlock((Handle)SpecialPixMapH);
- }
- if(SpecialPixMapH)DisposePixMap(SpecialPixMapH);
- }else{
- // Come here for a B&W port since there is no StdPix bottleneck for a B&W grafport.
- // By definition there isn't a custom StdPix bottleneck in a B&W grafport.
- // We'll let QuickTime figure out how to handle this case.
- CodecComponent theCodec;
-
- if ( theErr == noErr) {
- CodecInfo theInfo;
-
- // use the bestFidelityCodec if it is available, otherwise just use any
- theErr = GetCodecInfo(&theInfo, 'jpeg', bestFidelityCodec);
- if(theErr == noErr){
- theCodec = bestFidelityCodec;
- }else
- // we know this Codec exists because at startup we checked in the InitMacintosh proc
- theCodec = anyCodec;
- }
-
- theErr = FDecompressImage(theDataPtr, theDesc,
- dPixMap, &srcRect, NULL, ditherCopy,
- NULL, NULL, NULL, codecMaxQuality, theCodec, theAmountToRead,theDataProcRecord, NULL);
- }
- }
- HSetState(theDataHandle, hState);
- return theErr;
- }
- } /* DrawJPEGImage */
-
-
- static void DoTheOpenCommand()
- {
- OSErr theErr = noErr;
- OSType theTypes[] = { 'JPEG' };
- StandardFileReply theReply;
- Rect bounds;
- SInt16 windowTop = GetMBarHeight()+ 19;
- SInt16 right,bottom;
-
- // check to see if we already have a file reference. If so, we'll close the file since we're going to open a new one.
- if( gTheJPEGImage.theRefNum){
- FSClose(gTheJPEGImage.theRefNum);
- gTheJPEGImage.theRefNum = 0;
- }
-
- // disable the Print menu item since we can't print data anymore.
- DisableItem(GetMHandle(kFileMenuID), kPrintCommand);
-
- // Hide the existing window, if there is one.
- if(gTheWindow != NULL)HideWindow(gTheWindow);
-
- // Get a JPEG file and read the data.
- if(theErr == noErr){
- StandardGetFile(nil, 1, theTypes, &theReply);
- if (theReply.sfGood) {
- // Open the File so we have a refnum and read it
- theErr = FSpOpenDF(&theReply.sfFile, fsRdPerm, &gTheJPEGImage.theRefNum);
-
- if(theErr != noErr){
- ParamText("\pCan't Open the File", "\p", "\p", "\p");
- Alert(kGenericError, nil);
- return;
- }
-
- // Set the file reference number in the myDataLoad structure
- // that is stored in the dataRefCon field of the gTheICMDataProcRecord. We'll use this
- // if we need to use a DataLoading proc for our image.
- ((DataLoadPtr)gTheICMDataProcRecord.dataRefCon)->theRefNum = gTheJPEGImage.theRefNum;
-
- }else {
- // no file selected so just return.
- return;
- };
- };
-
- // Make a JPEG Image Description for the current image.
- if (theErr == noErr) theErr = MakeJPEGImageDescription(&gTheJPEGImage);
-
- if(theErr == iNotJPEGData){
- ParamText(
- "\pThe selected file either doesn't contain JPEG data or a JPEG version that can't be read by this program."
- , "\p", "\p", "\p");
- Alert(kGenericError, NULL);
-
- }
-
- // Set the bounds data in the JPEGData structure.
- if (theErr == noErr) theErr = SetJPEGBounds(&gTheJPEGImage);
-
-
-
- // Now make a Window of an appropriate size to hold our image. If we already
- // have a window then size it properly.
-
-
- // Max out the Window size at approximately the main screen size.
- if (theErr == noErr) {
- right = MIN(gTheJPEGImage.theBounds.right , qd.screenBits.bounds.right - kInsetBits );
- bottom = MIN(gTheJPEGImage.theBounds.bottom, qd.screenBits.bounds.bottom - (kInsetBits+windowTop) );
- SetRect(&bounds, 0 ,0 , right, bottom);
- }
-
- if (theErr == noErr){
-
- OffsetRect(&bounds, 0, windowTop);
-
- if(gTheWindow == NULL) {
- gTheWindow = NewCWindow(NULL, &bounds,
- (StringPtr)&(theReply.sfFile.name),
- false, noGrowDocProc, (WindowPtr)-1, true, 0);
- if (gTheWindow == NULL) {
- theErr = iMemFullErr;
- }
- } else{
- MoveWindow (gTheWindow, 0, windowTop, true);
- SetWTitle(gTheWindow, theReply.sfFile.name);
- SizeWindow (gTheWindow, bounds.right - bounds.left, bounds.bottom-bounds.top, true);
- }
- }
-
- if (theErr == noErr) {
- AlignWindow(gTheWindow, true, NULL, NULL);
- ShowWindow(gTheWindow);
- SetPort(gTheWindow);
- OffsetRect(&bounds, 0, -windowTop);
- ClipRect(&bounds);
- };
-
- // Since we have an image, we'll enable the 'Print' menu item.
-
- if (theErr == noErr) {
- EnableItem(GetMHandle(kFileMenuID), kPrintCommand);
- }
-
- // Invalidate the Window contents so we'll get an update event.
- if( theErr == noErr)InvalRect(&gTheWindow->portRect);
-
- DrawMenuBar();
-
- return;
- } /* DoTheOpenCommand */
-
- // Initialize the World and check whether the appropriate managers are available.
- static OSErr initMacintosh()
- {
- long version;
- OSErr theErr = noErr;
-
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- FlushEvents(everyEvent, 0);
- InitDialogs(NULL);
- TEInit();
- InitCursor();
- SetFractEnable(true); // I guess this urge comes from my old days at Adobe
-
- theErr = SetupMenus();
-
- if(theErr != noErr){
- ParamText("\pCouldn't load Menus.", "\p", "\p", "\p");
- }
-
- if(theErr == noErr){
- theErr = Gestalt(gestaltSystemVersion, &version);
- if( (theErr != noErr) || (version < 0x0700) ){
- ParamText("\pThis software requires System 7.0 or higher.", "\p", "\p", "\p");
- theErr = kAppError;
- }
- }
-
- if(theErr == noErr){
- theErr = Gestalt(gestaltQuickTimeVersion, &version);
- if( (theErr != noErr) ){
- ParamText("\pQuickTime not installed. This demo requires Quicktime.", "\p", "\p", "\p");
- }
- }
-
- if(theErr == noErr){
- theErr = Gestalt(gestaltCompressionMgr, &version);
- // Checking for version 1.5 of the ICM comes from the JFIF-PICT conversion program
- // provided as a sample program in the QuickTime section of the SDK. Apparently there
- // are problems with versions prior to version 1.5.
- if( (theErr != noErr || version < 15) ){
- if(theErr == noErr) theErr = kAppError;
- ParamText("\pVersion 1.5 or Greater of the Image Compression Mgr is required.", "\p", "\p", "\p");
- }
- }
-
- if(theErr == noErr){
- theErr = Gestalt(gestaltComponentMgr, &version);
- if( (theErr != noErr) ){
- ParamText("\pThe component manager is required but it isn't available.", "\p", "\p", "\p");
- }
- }
-
- if ( theErr == noErr) { // make sure there is some Codec available that can handle JPEG.
- CodecInfo theInfo;
-
- theErr = GetCodecInfo(&theInfo, 'jpeg', anyCodec);
- if(theErr != noErr)ParamText("\pThere don't appear to be any JPEG decompressors!", "\p", "\p", "\p");
- }
-
- if(theErr != noErr){
- Alert(kGenericError, NULL);
- }
-
- return theErr;
- } /* initMacintosh */
-
-
- static SInt16 handleEvent()
- {
- EventRecord e;
- WindowRecord *w;
- SInt32 s;
- Rect b;
- RgnHandle currentGrayRegion;
- OSErr theErr;
- GrafPtr oldPort;
-
- if (WaitNextEvent(everyEvent, &e, kSleepTime, 0L))
- {
- switch (e.what)
- {
- case mouseDown:
- switch (FindWindow(e.where, (WindowPtr *)&w))
- {
- case inContent:
- if ((WindowRecord *) FrontWindow() != w)
- SelectWindow((WindowPtr)w);
- else if (((WindowRecord *) w)->windowKind < 0)
- SystemClick(&e, (WindowPtr )w);
- break;
- case inDrag:
- currentGrayRegion = GetGrayRgn();
- b = (**(RgnHandle)currentGrayRegion).rgnBBox;
- // make sure drags align well for best performance in redraws.
- DragAlignedWindow((WindowPtr )w, e.where, &b, NULL, NULL);
- break;
- case inGoAway:
- if (TrackGoAway((WindowPtr )w, e.where)){
- // we should close the file here...
- if(gTheJPEGImage.theRefNum){
- FSClose(gTheJPEGImage.theRefNum);
- gTheJPEGImage.theRefNum = 0;
- }
- HideWindow((WindowPtr )w);
- DisableItem(GetMHandle(kFileMenuID), kPrintCommand);
- DrawMenuBar();
- }
- break;
- case inGrow:
- SetRect(&b, 30, 30, 0x7fff, 0x7fff);
- s = GrowWindow((WindowPtr )w, e.where, &b);
- if (s){
- SizeWindow((WindowPtr )w, LoWord(s), HiWord(s), 1);
- SetPort((WindowPtr )w);
- InvalRect(&gTheWindow->portRect);
- }
- break;
- case inZoomIn:
- if (TrackBox((WindowPtr )w, e.where, inZoomIn)){
- ZoomWindow((WindowPtr )w, inZoomIn, 0);
- SetPort((WindowPtr )w);
- InvalRect(&gTheWindow->portRect);
- }
- break;
- case inZoomOut:
- if (TrackBox((WindowPtr )w, e.where, inZoomOut)){
- ZoomWindow((WindowPtr )w, inZoomOut, 0);
- SetPort((WindowPtr )w);
- InvalRect(&gTheWindow->portRect);
- }
- break;
- case inMenuBar:
- {
- SInt32 mResult = MenuSelect(e.where);
- SInt16 theMenu, theItem;
- theMenu = HiWord(mResult);
- theItem = LoWord(mResult);
- doCommand(theMenu, theItem);
- break;
- }
- }
- break;
- case updateEvt:
- BeginUpdate((WindowPtr)e.message);
- GetPort(&oldPort);
- SetPort((WindowPtr)e.message);
-
- theErr = DrawJPEGImage(gTheJPEGImage,ISCOLORPORT((WindowPtr)e.message));
-
- SetPort(oldPort);
- EndUpdate((WindowPtr)e.message);
-
- break;
- case keyDown:
- case autoKey:
- DoKeyDown(&e);
- break;
- default: break;
-
- } /* switch */
- } /* if */
- return 1;
- } /* handleEvent */
-
-
- static OSErr SetupMenus(void)
- {
- OSErr theErr = noErr;
- Handle MyMBar;
-
- MyMBar = GetNewMBar(128);
- if(MyMBar) {
- SetMenuBar(MyMBar);
- AddResMenu(GetMHandle(kAppleMenuID),'DRVR');
- DisableItem(GetMHandle(kFileMenuID), kPrintCommand);
- DrawMenuBar();
- } else {
- theErr = kCouldntLoadMenu;
- }
- return theErr;
- } /* SetupMenus */
-
- static void DoKeyDown(myEvent)
- EventRecord *myEvent;
- {
- unsigned char charCode = (unsigned char) (myEvent->message & charCodeMask);
-
- if (myEvent->modifiers & cmdKey)
- { /* command key */
- SInt32 mResult = MenuKey(charCode);
- SInt16 theMenu = HiWord(mResult);
- SInt16 theItem = LoWord(mResult);
- doCommand(theMenu, theItem);
- }
- return ;
- } /* KeyDown */
-
-
- /*
- Display the About dialog.
- */
- static void showAboutMeDialog()
- {
- GrafPtr savePort;
- SInt16 itemHit;
- DialogPtr theDialog;
-
- GetPort(&savePort);
- theDialog = GetNewDialog(kAboutMeDLOG, NULL, (WindowPtr) -1);
- SetPort(theDialog);
-
- do { ModalDialog(NULL, &itemHit); } while (itemHit != kOKButton);
-
- CloseDialog(theDialog);
-
- SetPort(savePort);
- return;
- } /* showAboutMeDialog */
-
- /*
- * Process Menu Selections
- */
- static void doCommand(SInt16 theMenu,SInt16 theItem)
- {
- OSErr theErr = noErr ;
-
- switch (theMenu)
- {
- case kAppleMenuID:
- if (theItem == kAboutMeCommand)
- {
- showAboutMeDialog();
- }
- else
- {
- GrafPtr savePort;
- Str255 daName;
- GetItem(GetMHandle(kAppleMenuID), theItem, daName);
- GetPort(&savePort);
- (void) OpenDeskAcc(daName);
- SetPort(savePort);
- }
- break;
-
- case kFileMenuID:
- switch (theItem)
- {
- case kOpenCommand:
- DoTheOpenCommand();
- break;
- case kSaveCommand:
- break;
- case kPageSetupCommand:
-
- PrOpen();
- theErr = PrError();
-
- if(theErr == noErr ){
- PrValidate( gPrinterRecord );
- theErr = PrError();
- }
-
- if(theErr == noErr){
- PrStlDialog(gPrinterRecord);
- theErr = PrError();
- }
- PrClose();
-
- if(theErr != noErr){
- Str255 scratchString;
- NumToString((long)theErr, scratchString);
- ParamText("\pThere was a print manager error.", scratchString, "\p", "\p");
- Alert(kGenericError, NULL);
- }
- break;
- case kPrintCommand:
- theErr = Print(gTheJPEGImage, gPrinterRecord);
-
- if(theErr != noErr){
- Str255 scratchString;
- NumToString((long)theErr, scratchString);
- ParamText("\pThere was an error during printing.", scratchString, "\p", "\p");
- Alert(kGenericError, NULL);
- }
- break;
- case kQuitCommand:
- ExitToShell();
- break;
- default:
- break;
- }
- break;
-
- case kEditMenuID:
- /*
- * Run this through SystemEdit first.
- * SystemEdit will return FALSE if it's not a system window.
- */
- if (SystemEdit(theItem-1)) break;
-
- default:
- break;
- } /* switch theMenu */
-
- HiliteMenu(0);
- return;
- } /* doCommand */
-
-
- static OSErr Print(JPEGImage theJPEGImage, THPrint thePrintRecord)
- {
- OSErr theDrawingErr = noErr;
- OSErr aPrintingErr = noErr;
-
- GrafPtr oldPort;
- TPrStatus thePrinterStatus;
- TPPrPort PrinterPort;
- Boolean OKToPrint;
-
- GetPort( &oldPort );
-
- PrOpen();
-
- if( PrError() == noErr){
- PrValidate(thePrintRecord);
- if( PrError() == noErr){
- OKToPrint = PrJobDialog(thePrintRecord);
- if(OKToPrint){
- PrinterPort = PrOpenDoc(thePrintRecord,NULL,NULL);
- if(PrError() == noErr){
- PrOpenPage(PrinterPort,NULL);
- if(PrError() == noErr){
- theDrawingErr = DrawJPEGImage(theJPEGImage,ISCOLORPORT((GrafPtr)PrinterPort));
- }
- PrClosePage(PrinterPort);
- }
- PrCloseDoc(PrinterPort);
- if(
- ( (*thePrintRecord)->prJob.bJDocLoop == bSpoolLoop ) &&
- ( PrError() == noErr )
- ){
- PrPicFile(thePrintRecord,NULL,NULL,NULL, &thePrinterStatus);
- }
- }
- }
- }
- aPrintingErr = PrError();
- PrClose();
- SetPort(oldPort);
- return ( (aPrintingErr == noErr) ? theDrawingErr : aPrintingErr) ;
- } /* Print */
-
- // This is our data loading procedure to load the data off the disk on an as needed basis.
- // It will be called by QuickTime as a result of our StdPix or FDecompress function call.
-
- static pascal OSErr MyDataLoadingProc(Ptr *dataP, long bytesNeeded, long refcon)
- {
- OSErr theErr = noErr;
-
- if(dataP != NULL){
- DataLoadPtr theDataLoadPtr = (DataLoadPtr)refcon;
- Ptr theDataBufferP = StripAddress(*(theDataLoadPtr->theDataBufferH));
- long theBufferSize = theDataLoadPtr->theBufferSize;
- short theRefNum = theDataLoadPtr->theRefNum;
-
- // calculate the number of bytes left in our existing data buffer. This is
- // the size of the buffer itself minus the distance we are from the start
- // of the buffer.
-
- long bytesAvail = theBufferSize - (*dataP - theDataBufferP);
-
- // do we already have enough bytes in our buffer for this call to our data loading
- // procedure? If so we don't need to read any additional data.
- if(bytesNeeded > bytesAvail){
-
- // we come here if we don't have enough bytes of data in our buffer. First
- // figure out how many bytes we should read to refill up the buffer.
- long bytesToRead = theBufferSize - bytesAvail;
-
- // if there are bytes available at the end of our buffer then move them
- // to the beginning of the buffer
- if(bytesAvail) BlockMove(*dataP,theDataBufferP, bytesAvail);
-
- // now go ahead and fill up the remainder of the buffer, starting at the
- // location just after the last valid byte in the buffer
- theErr = FSRead(theRefNum, &bytesToRead, theDataBufferP + bytesAvail);
-
- // ignore end of file errors
- if(theErr == eofErr)theErr = noErr;
-
- // we reset the data pointer used by the caller of the data loading function
- // so that it points to the first byte of valid data, which is the beginning of our buffer.
- *dataP = theDataBufferP;
- }
- }else{
- // Come here for the data mark reset case. The implementation we are providing here
- // doesn't know how to reset the stream so we return an error. I haven't seen
- // a data mark reset as part of JPEG decoding.
-
- // Not handling the data mark reset case slows down PhotoCD significantly.
- // Demonstrating how to do this better will have to wait for another article.
- theErr = -1;
- }
- return theErr;
- }
-
-
- // SetJPEGBounds sets 'theBounds' field of the JPEG data structure. This relies on the
- // ImageDescription field having already been filled in.
- static OSErr SetJPEGBounds(JPEGImage *theJPEGImage)
- {
- Rect *theBounds = &(*theJPEGImage).theBounds;
- ImageDescriptionHandle theDesc = (*theJPEGImage).theDesc;
-
- if(theDesc == NULL)return kAppError;
-
- theBounds->top = theBounds->left = 0;
-
- theBounds->right = (*theDesc)->width;
- theBounds->bottom = (*theDesc)->height;
- return noErr;
- } /* SetJPEGBounds */
-
- // MakeJPEGImageDescription creates a QuickTime image description record based on the JPEG data.
- static OSErr MakeJPEGImageDescription(JPEGImage *theJPEGImage)
- {
- OSErr theErr = noErr;
- CodecInfo theInfo;
- short width,height;
- ImageDescriptionHandle desc;
- char *scanData;
- long hRes = 72L<<16 , vRes = 72L<<16;
- short depth = 32;
-
- long dataAmtToRead,filesize;
- Handle theDataBufferH =((DataLoadPtr)gTheICMDataProcRecord.dataRefCon)->theDataBufferH;
- Ptr theDataPtr;
-
- if((*theJPEGImage).theDesc == NULL){
- (*theJPEGImage).theDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
- if((*theJPEGImage).theDesc == NULL || (MemError() != noErr)){
- theErr = iMemFullErr;
- return theErr;
- }
- }
-
- HLock(theDataBufferH);
- theDataPtr = StripAddress(*theDataBufferH);
-
- // make sure we are pointed to the beginning of the file to read.
- theErr = SetFPos(theJPEGImage->theRefNum, fsFromStart, 0);
-
- // get the size of the file
- if(theErr == noErr)theErr = GetEOF(theJPEGImage->theRefNum, &filesize);
-
- // again, make sure we are pointed to the beginning of the file to read.
- if(theErr == noErr)theErr = SetFPos(theJPEGImage->theRefNum, fsFromStart, 0);
-
- // we either read all the data or a whole buffer full, depending on whether it fits in our buffer.
- dataAmtToRead = MIN(filesize,((DataLoadPtr)gTheICMDataProcRecord.dataRefCon)->theBufferSize);
-
- // go ahead and read the data.
- if(theErr == noErr)theErr = FSRead(theJPEGImage->theRefNum, &dataAmtToRead,theDataPtr);
-
- // Scan the JPEG image data and find the width, height, resolution, and depth of the image.
-
- // Note that MarkerDetect was written to expect that the pointer to the buffer passed in points to
- // a buffer with all the JPEG data. Here we only have 1 data buffer's worth. This isn't a problem here
- // since 32k (our minimum buffer size) should contain all the information we are scanning for.
-
- // The comment in MarkerDetect that it returns a pointer to the beginning of the image data
- // is misleading in this case. The returned pointer does point to image data, but not all of
- // the data is in memory unless it fits in our buffer size. This isn't a problem for us since
- // we only use the pointer returned from MarkerDetect to see if the data is valid.
-
- if ( (scanData = MarkerDetect((char *)theDataPtr,&width,&height,&hRes,&vRes,&depth)) == 0 ) {
- theErr = iNotJPEGData;
- }
-
- // This chooses the Codec that can handle JPEG data with the best Fidelity. If that returns an
- // error we'll try and use the best we can find that can handle JPEG.
- // This will only be used if we are decompressing the data on the host instead
- // of the printer.
- if ( theErr == noErr) {
- theErr = GetCodecInfo(&theInfo, 'jpeg', bestFidelityCodec);
- if(theErr != noErr)
- theErr = GetCodecInfo(&theInfo, 'jpeg', anyCodec); // we know this exists because we check at
- // at App startup in the InitMacintosh proc
- }
- // Set up the ImageDescription based on the JPEG Codec and the JPEG image data.
- if ( theErr == noErr){
- desc = (*theJPEGImage).theDesc;
-
- (*desc)->idSize = sizeof(ImageDescription);
- (*desc)->cType = 'jpeg';
- (*desc)->resvd1 = (*desc)->resvd2 = (*desc)->dataRefIndex = 0;
- (*desc)->version = theInfo.version;
- (*desc)->revisionLevel = theInfo.revisionLevel;
- (*desc)->vendor = theInfo.vendor;
- (*desc)->temporalQuality = 0;
- (*desc)->spatialQuality = codecMaxQuality;
- (*desc)->width = width;
- (*desc)->height = height;
- (*desc)->hRes = hRes;
- (*desc)->vRes = vRes;
- (*desc)->dataSize = filesize;
- (*desc)->frameCount = 1;
- BlockMove(theInfo.typeName, (*desc)->name, 32);
- (*desc)->depth = depth;
- (*desc)->clutID = -1;
- }
- HUnlock(theDataBufferH);
- return theErr;
- } /* MakeJPEGImageDescription */
-
-
- /*
-
- JPEG specific stuff. Taken almost literally from the Macintosh OS SDK.
- This is from the JFIF-PICT conversion program provided as a sample program
- in the QuickTime section of the SDK. The only change was to allow
- JFIF version 1.02 to be used with this application.
-
- */
-
- /*
-
- Scan the JPEG stream for the proper markers and fill in the image parameters
-
- returns NULL if it can't comprehend the data, otherwise a pointer to the start
- of the JPEG data.
-
-
- It does a cursory check on the JPEG data to see if it's reasonable.
- Check out the ISO JPEG spec if you really want to know what's going on here.
-
- */
-
- static char *
- MarkerDetect(char *data,short *width,short *height,long *hRes,long *vRes,short *depth)
- {
- short frame_field_length;
- short data_precision;
- short scan_field_length;
- short number_component,scan_components;
- short c1,hv1,q1,c2,hv2,q2,c3,hv3,q3;
- short dac_t1, dac_t2, dac_t3;
- unsigned char c;
- short qtabledefn;
- short htabledefn;
- short status;
- short length;
- short i;
-
- c = *data++;
- qtabledefn = 0;
- htabledefn = 0;
- status = 0;
- while (c != (unsigned char)MARKER_SOS) {
- while (c != (unsigned char)MARKER_PREFIX)
- c = *data++; /* looking for marker prefix bytes */
- while (c == (unsigned char)MARKER_PREFIX)
- c = *data++; /* (multiple?) marker prefix bytes */
- if (c == 0)
- continue; /* 0 is never a marker code */
-
- if (c == (unsigned char)MARKER_SOF) {
-
- frame_field_length = *(short *)data;
- data += 2;
- data_precision = *data++;
-
- if ( data_precision != 8 ) {
- status = 2;
- }
-
- *height = *(short *)data;
- data += 2;
- *width = *(short *)data;
- data += 2;
-
- number_component = *data++;
-
- switch ( number_component ) {
- case 3:
- c1 = *data++;
- hv1 = *data++;
- q1 = *data++;
- c2 = *data++;
- hv2 = *data++;
- q2 = *data++;
- c3 = *data++;
- hv3 = *data++;
- q3 = *data++;
- *depth = 32;
- break;
- case 1:
- c1 = *data++;
- hv1 = *data++;
- q1 = *data++;
- *depth = 40;
- break;
- default:
- status = 3;
- break;
- }
- continue;
- }
-
- if (c == (unsigned char)MARKER_SOS) {
- short tn;
- scan_field_length = *(short *)data;
- data += 2;
- scan_components = *data++;
- for ( i=0; i < scan_components; i++ ) {
- unsigned char cn,dac_t;
-
- cn = *data++;
- dac_t = *data++;
- if ( cn == c1 ) {
- dac_t1 = dac_t;
- } else if ( cn == c2 ) {
- dac_t2 = dac_t;
- } else if ( cn == c3 ) {
- dac_t3 = dac_t;
- } else {
- status = 29;
- break;
- }
- }
- switch ( tn=(dac_t1 & 0xf) ) {
- case 0:
- case 1:
- break;
- case 0xf:
- break;
- default:
- status = 33;
- break;
- }
- switch ( tn=(dac_t2 & 0xf) ) {
- case 0:
- case 1:
- break;
- case 0xf:
- break;
- default:
- status = 33;
- break;
- }
- switch ( tn=(dac_t3 & 0xf) ) {
- case 0:
- case 1:
- break;
- case 0xf:
- break;
- default:
- status = 33;
- break;
- }
-
-
- /* Initialize the DC tables */
-
- switch ( tn=dac_t1 & 0xf0 ) {
- case 0:
- case 0x10:
- break;
- case 0xf0:
- break;
- default:
- status = 34;
- break;
- }
- switch ( tn=dac_t2 & 0xf0 ) {
- case 0:
- case 0x10:
- break;
- case 0xf0:
- break;
- default:
- status = 34;
- break;
- }
- switch ( tn=dac_t3 & 0xf0 ) {
- case 0:
- case 0x10:
- break;
- case 0xf0:
- break;
- default:
- status = 34;
- break;
- }
- if ( *data++ != 0 ) {
- // status = 18;
- }
- if ( *data++ != 63 ) {
- // status = 19;
- }
- if ( *data++ != 0 ) {
- // status = 20;
- }
- if ( status )
- return(0);
- else
- return(data);
- }
-
- if (c == (unsigned char)MARKER_DQT) {
- scan_field_length = *(short *)data;
- SwallowQuantTable(data);
- data += scan_field_length;
- continue;
- }
- if (c == (unsigned char)MARKER_DHT) {
- scan_field_length = *(short *)data;
- SwallowHuffTable(data);
- continue;
- }
- if (c == (unsigned char)MARKER_DRI) {
- length = *(short *)data; /* read length */
- data += 2;
- length = *(short *)data;
- data += 2;
- continue;
- }
- if (c == (unsigned char)MARKER_DNL) {
- length = *(short *)data; /* read length */
- data += 2;
- length = *(short *)data;
- data += 2;
- continue;
- }
- if (c >= (unsigned char)0xD0 && c <= (unsigned char)0xD7) {
- continue;
- }
-
- if (c == (unsigned char)MARKER_SOI || c == (unsigned char)MARKER_EOI) /* image start, end marker */
- continue;
-
- if ( (c >= (unsigned char)0xC1 && c <= (unsigned char)0xcF) || (c == (unsigned char)0xde) || (c == (unsigned char)0xdf) ) {
- status = 12;
- length = *(short *)data; /* read length */
- data += length;
- continue;
- }
- if (c >= (unsigned char)MARKER_APP0 && c <= (unsigned char)0xEF) {
- length = *(short *)data; /* read length */
- data += 2;
- length -= 2;
- if ( (c == (unsigned char)MARKER_APP0) && length > 5 ) { /* check for JFIF marker */
- char buf[5];
- buf[0] = *data++;
- buf[1] = *data++;
- buf[2] = *data++;
- buf[3] = *data++;
- buf[4] = *data++;
- length -= 5;
-
- if ( buf[0] == 'J' && buf[1] == 'F' && buf[2] == 'I' && buf[3] == 'F' ) {
- short units;
- long xres,yres;
- short version;
-
-
- version = *(short *)data; data += 2;length -= 2;
- if ( version != 0x100 && version != 0x101 && version != 0x102 ) { // DMG - added version 102
- status = 44; // unknown JFIF version
- break;
- }
- units = *data++; length--;
- xres = *(short *)data; data += 2; length -= 2;
- yres = *(short *)data; data += 2; length -= 2;
-
- switch ( units ) {
- case 0: // no res, just aspect ratio
- *hRes = FixMul(72L<<16,xres<<16);
- *vRes = FixMul(72L<<16,yres<<16);
- break;
- case 1: // dots per inch
- *hRes = xres<<16;
- *vRes = yres<<16;
- break;
- case 2: // dots per centimeter (we convert to dpi )
- *hRes = FixMul(0x28a3d,xres<<16);
- *vRes = FixMul(0x28a3d,xres<<16);
- break;
- default:
- break;
- }
- xres = *data++; length--;
- yres = *data++; length--;
-
- /* skip JFIF thumbnail */
-
- xres *= yres;
- data += xres*3; length -= xres*3;
-
- if ( length != 0 ) {
- status = 44; // bad jfif marker
- break;
- }
- }
- }
- data += length;
- continue;
- }
- if (c == (unsigned char)MARKER_COM) {
- length = *(short *)data; /* read length */
- data += length;
- continue;
- }
- if (c >= (unsigned char)0xf0 && c <= (unsigned char)0xfd) {
- length = *(short *)data; /* read length */
- data += length;
- continue;
- }
- if ( c == 0x1 )
- continue;
- if ( (c >= (unsigned char)0x2 && c <= (unsigned char)0xbF) ) {
- length = *(short *)data; /* read length */
- status = 13;
- data += length;
- continue;
- }
- }
- return(0);
- }
-
-
- /*
- Read the quantization table from the JPEG bitstream.
- */
-
- static void
- SwallowQuantTable(char *data)
- {
- long i;
- long length,pm,nm;
-
- length = *(short *)data; /* read length */
- length -= 2;
- data += 2;
- while ( length ) {
- nm= *data++; /* read precision and number */
- pm = nm>>4;
- nm &= 0xf;
- length--;
- if ( pm ) {
- for(i=0;i<64;i++) {
- length -= 2;
- data += 2;
- }
- } else {
- for(i=0;i<64;i++) {
- length--;
- data++;
- }
- }
- }
- }
-
- /*
- Read the huffman table from the JPEG bitstream.
- */
-
- static void
- SwallowHuffTable(char *data)
- {
- short i,tc,id;
- long length;
-
- unsigned char bin[17];
- unsigned char val[256];
-
- bin[0] = 0;
- length = *(short *)data; /* read length */
- data += 2;
- length -= 2;
- while ( length ) {
- id=*data++; /* read id */
- length--;
- if ( id != 0 && id != 1 && id != 0x10 && id != 0x11) {
- return;
- }
- tc = 0;
- for(i=0;i<16;i++) {
- length--;
- tc += (bin[i+1] = *data++);
- }
- for (i=0; i < tc; i++ ) {
- length--;
- val[i] = *data++;
- }
- }
- }
-
-
-
-
-
-